<html>
  <head>
    <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>iOS 证书配置指北 - Rubin&#39;s Blog</title>
<meta name="description" content="温故而知新" />
<link rel="shortcut icon" href="https://jrb1995.gitee.io/favicon.ico?v=1588066216187">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.10.0/katex.min.css">
<link href="https://cdn.jsdelivr.net/npm/remixicon@1.3.1/fonts/remixicon.css" rel="stylesheet">
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Droid+Serif:400,700">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/3.7.2/animate.min.css">

<link rel="stylesheet" href="https://jrb1995.gitee.io/styles/main.css">
<link rel="alternate" type="application/atom+xml" title="iOS 证书配置指北 - Rubin&#39;s Blog - Atom Feed" href="https://jrb1995.gitee.io/atom.xml">



  </head>
  <body>
    <div id="app" class="main px-4 flex flex-col lg:flex-row">
      <div id="sidebar" class="sidebar-wrapper lg:static lg:w-1/4">
  <div class="lg:sticky top-0">
    <div class="sidebar-content">
      <div class="flex lg:block p-4 lg:px-0 items-center fixed lg:static lg:block top-0 right-0 left-0 bg-white z-50">
        <i class="remixicon-menu-2-line lg:mt-4 text-2xl cursor-pointer animated fadeIn" onclick="openMenu()"></i>
        <a href="https://jrb1995.gitee.io">
          <img class="animated fadeInLeft avatar rounded-lg mx-4 lg:mt-32 lg:mx-0 mt-0 lg:w-24 lg:h-24 w-12 w-12" src="https://jrb1995.gitee.io/images/avatar.png?v=1588066216187" alt="">
        </a>
        <h1 class="animated fadeInLeft lg:text-4xl font-extrabold lg:mt-8 mt-0 text-xl" style="animation-delay: 0.2s">Rubin&#39;s Blog</h1>
      </div>
      
        <div class="animated fadeInLeft" style="animation-delay: 0.4s">
          <p class="my-4 text-gray-600 font-light hidden lg:block">
            文章目录
          </p>
          <div class="toc-container hidden lg:block">
            <ul class="markdownIt-TOC">
<li>
<ul>
<li><a href="#%E5%89%8D%E8%A8%80">前言</a></li>
<li><a href="#%E5%88%9B%E5%BB%BA%E5%BA%94%E7%94%A8%E7%A8%8B%E5%BA%8F-id">创建应用程序 ID</a></li>
<li><a href="#%E5%88%9B%E5%BB%BA-csr-%E6%96%87%E4%BB%B6%E8%AF%81%E4%B9%A6%E8%AF%B7%E6%B1%82%E6%96%87%E4%BB%B6">创建 CSR 文件（证书请求文件）</a></li>
<li><a href="#%E5%88%9B%E5%BB%BA%E8%AF%81%E4%B9%A6">创建证书</a>
<ul>
<li><a href="#%E6%8E%A8%E9%80%81%E8%AF%81%E4%B9%A6%E5%92%8C%E6%9E%81%E5%85%89%E6%8E%A8%E9%80%81">推送证书和极光推送</a></li>
</ul>
</li>
<li><a href="#%E5%88%9B%E5%BB%BA%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6">创建配置文件</a></li>
<li><a href="#%E5%85%B6%E4%BB%96%E9%97%AE%E9%A2%98">其他问题</a>
<ul>
<li><a href="#xcode-missing-private-key-%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88">Xcode Missing Private key 解决方案</a></li>
</ul>
</li>
</ul>
</li>
</ul>

          </div>
        </div>
      
    </div>
  </div>
</div>

<div class="menu-container">
  <i class="remixicon-arrow-left-line text-2xl cursor-pointer animated fadeIn close-menu-btn" onclick="closeMenu()"></i>
  <div>
    
      
        <a href="/" class="menu" style="animation-delay: 0s">
          首页
        </a>
      
    
      
        <a href="/archives" class="menu" style="animation-delay: 0.2s">
          归档
        </a>
      
    
      
        <a href="/tags" class="menu" style="animation-delay: 0.4s">
          标签
        </a>
      
    
      
        <a href="/post/about" class="menu" style="animation-delay: 0.6000000000000001s">
          关于
        </a>
      
    
  </div>
  <div class="site-footer">
    <div class="py-4 text-gray-700">Powered by <a href="https://github.com/getgridea/gridea" target="_blank">Gridea</a></div>
    <a class="rss" href="https://jrb1995.gitee.io/atom.xml" target="_blank">RSS</a>
  </div>
</div>
<div class="mask" onclick="closeMenu()">
</div>
      <div class="content-wrapper py-32 lg:p-8 lg:w-3/4 post-detail animated fadeIn">
        <h1 class="text-3xl font-bold lg:mt-16">iOS 证书配置指北</h1>
        <div class="text-sm text-gray-700 lg:my-8">
          2020-04-06 / 4 min read
        </div>
        
          <img class="post-feature-image rounded-lg mx-auto my-4" src="https://jrb1995.gitee.io/post-images/ios-zheng-shu-pei-zhi-zhi-bei.png" alt="">
        
        <div class="post-content yue">
          <h2 id="前言">前言</h2>
<p>用 react-native 开发项目时，在对 iOS 证书相关的配置，每次操作一遍后过一段时间又忘了。所以将证书的配置流程都记录下来，方便以后查阅。</p>
<h2 id="创建应用程序-id">创建应用程序 ID</h2>
<p>首先需要开发者账号，登录<a href="https://developer.apple.com/" target="_blank">苹果开发者网站</a>进入开发者账户。</p>
<figure data-type="image" tabindex="1"><img src="https://jrb1995.gitee.io/post-images/1586741039119.png" alt="" loading="lazy"></figure>
<p>进入 <code>Certificates, Identifiers &amp; Profiles</code> 页面。</p>
<figure data-type="image" tabindex="2"><img src="https://jrb1995.gitee.io/post-images/1586141548388.png" alt="" loading="lazy"></figure>
<p>选择 Identifiers 创建 App ID，填写 App ID 的 Description 和 Bundle ID。</p>
<figure data-type="image" tabindex="3"><img src="https://jrb1995.gitee.io/post-images/1586141828211.png" alt="" loading="lazy"></figure>
<p>一般选择 App IDs 即可。</p>
<figure data-type="image" tabindex="4"><img src="https://jrb1995.gitee.io/post-images/1586141936519.png" alt="" loading="lazy"></figure>
<figure data-type="image" tabindex="5"><img src="https://jrb1995.gitee.io/post-images/1586142154922.png" alt="" loading="lazy"></figure>
<p>为 App 添加一些功能，比如消息推送功能。</p>
<figure data-type="image" tabindex="6"><img src="https://jrb1995.gitee.io/post-images/1586142360020.png" alt="" loading="lazy"></figure>
<figure data-type="image" tabindex="7"><img src="https://jrb1995.gitee.io/post-images/1586142366600.png" alt="" loading="lazy"></figure>
<p>填写好以上信息后，点击 Continue，确认 AppId 正确填写，点击 Register，注册 AppId 成功。</p>
<h2 id="创建-csr-文件证书请求文件">创建 CSR 文件（证书请求文件）</h2>
<blockquote>
<p>CSR（Certificate Signing Request）即证书请求文件。证书申请者在申请数字证书时由 CSP（加密服务提供者）在生成私钥的同时也生成证书请求文件（CSR 文件），证书申请者只要把 CSR 文件提交给证书颁发机构后（创建 App ID 时上传到苹果后台），证书颁发机构使用其根证书私钥签名生成证书公钥文件（开发者证书）。</p>
</blockquote>
<p>CSR 文件在创建 Certificates 时需要上传。</p>
<p>使用 Mac 自带的 <code>钥匙串访问</code> 来创建 <code>Certificate Signing Request</code> 文件，如下图操作：</p>
<figure data-type="image" tabindex="8"><img src="https://jrb1995.gitee.io/post-images/1586143369160.png" alt="" loading="lazy"></figure>
<p>填写 <code>用户邮箱</code> 和 <code>常用名称</code> (名称可以随意填)，并选择 <code>存储到磁盘</code>，文件后缀为 <code>.certSigningRequest</code>。</p>
<figure data-type="image" tabindex="9"><img src="https://jrb1995.gitee.io/post-images/1586143624913.png" alt="" loading="lazy"></figure>
<h2 id="创建证书">创建证书</h2>
<blockquote>
<p>iOS 证书是用来证明 iOS App 内容（executable code）的合法性和完整性的数字证书。对于想安装到真机或发布到 AppStore 的应用程序（App），只有经过签名验证（Signature Validated）才能确保来源可信，并且保证 App 内容是完整、未经篡改的。</p>
</blockquote>
<p>选择 Certificates 点击加号。</p>
<figure data-type="image" tabindex="10"><img src="https://jrb1995.gitee.io/post-images/1586144322541.png" alt="" loading="lazy"></figure>
<p>选择相应的证书种类，如图有开发调试证书、生产发布证书（App Store 上传应用商店、Ad Hoc 用于测试包发布）、开发环境推送证书、生产环境推送证书。选择你需要的证书。</p>
<figure data-type="image" tabindex="11"><img src="https://jrb1995.gitee.io/post-images/1586236889292.png" alt="" loading="lazy"></figure>
<figure data-type="image" tabindex="12"><img src="https://jrb1995.gitee.io/post-images/1586236895832.png" alt="" loading="lazy"></figure>
<p>再点击 Continue，选择之前生成的 CSR 文件上传，继续点击 Continue，证书创建完成。下载下来添加到钥匙串访问中。</p>
<figure data-type="image" tabindex="13"><img src="https://jrb1995.gitee.io/post-images/1586229786987.png" alt="" loading="lazy"></figure>
<figure data-type="image" tabindex="14"><img src="https://jrb1995.gitee.io/post-images/1586229914720.png" alt="" loading="lazy"></figure>
<h3 id="推送证书和极光推送">推送证书和极光推送</h3>
<p>项目中需要消息推送服务的话，就需要用的消息推送证书。我使用的是极光推送，把消息推送证书 Download 下来，双击添加到钥匙串访问中。找到刚才下载的证书并导出 <code>.p12</code> 文件，之后需要添加到极光后台。</p>
<figure data-type="image" tabindex="15"><img src="https://jrb1995.gitee.io/post-images/1586235903947.png" alt="" loading="lazy"></figure>
<p>点击存储后需要输入密码，密码要记住，上传到极光后台需要用到。</p>
<figure data-type="image" tabindex="16"><img src="https://jrb1995.gitee.io/post-images/1586236061023.png" alt="" loading="lazy"></figure>
<p>假设你的极光后台应用信息已经填写好，设置证书时如下图：</p>
<figure data-type="image" tabindex="17"><img src="https://jrb1995.gitee.io/post-images/1586236293643.png" alt="" loading="lazy"></figure>
<p>上传之前导出的 <code>.p12</code> 文件，填写导出时设置的密码，极光会在后台为你的应用进行鉴权。</p>
<figure data-type="image" tabindex="18"><img src="https://jrb1995.gitee.io/post-images/1586236303663.png" alt="" loading="lazy"></figure>
<h2 id="创建配置文件">创建配置文件</h2>
<p>创建 Provisioning Profile 的前提，已在 Apple Developer 网站创建待发布应用所使用的 Bundle ID 的 App ID。</p>
<p>选择 Profile 点击加号按钮，创建 Provisioning Profile。</p>
<figure data-type="image" tabindex="19"><img src="https://jrb1995.gitee.io/post-images/1586230645086.png" alt="" loading="lazy"></figure>
<p>选择你需要的 Profile 环境。</p>
<figure data-type="image" tabindex="20"><img src="https://jrb1995.gitee.io/post-images/1586237441979.png" alt="" loading="lazy"></figure>
<p>选择之前创建的 App ID、相应的证书、测试的设备、profile 名称，一直 Continue 即可。</p>
<figure data-type="image" tabindex="21"><img src="https://jrb1995.gitee.io/post-images/1586231384208.png" alt="" loading="lazy"></figure>
<figure data-type="image" tabindex="22"><img src="https://jrb1995.gitee.io/post-images/1586231669480.png" alt="" loading="lazy"></figure>
<figure data-type="image" tabindex="23"><img src="https://jrb1995.gitee.io/post-images/1586231591517.png" alt="" loading="lazy"></figure>
<figure data-type="image" tabindex="24"><img src="https://jrb1995.gitee.io/post-images/1586234979603.png" alt="" loading="lazy"></figure>
<p>填写完 Profile Name 点击 generate 完成，之后点击 DownLoad，下载 <code>.mobileprovision</code> 的文件，双击文件即可添加到 Xcode。</p>
<figure data-type="image" tabindex="25"><img src="https://jrb1995.gitee.io/post-images/1586235137886.png" alt="" loading="lazy"></figure>
<p>至此证书和配置文件之类的都创建完了。</p>
<h2 id="其他问题">其他问题</h2>
<h3 id="xcode-missing-private-key-解决方案">Xcode Missing Private key 解决方案</h3>
<p>当我们换另一台 Mac 设备开发打包的时候，会发现提示 <code>Missing Private key</code>。</p>
<p>因为苹果规定 <code>.cer</code> 证书只能存在于一台机器上，因此如果另一台电脑想要用的话，需要导出为 <code>.p12</code> 文件，安装到另一台没有安装 <code>.cer</code> 文件的 Mac 电脑。</p>
<p>详细说明参考该篇博客 <a href="https://www.jianshu.com/p/6372055fbaa0" target="_blank">https://www.jianshu.com/p/6372055fbaa0</a></p>

        </div>

        
          <a class="animated fadeInUp p-2 items-center text-sm text-gray-700 border hover:bg-gray-300 leading-none rounded-full flex lg:inline-flex m-4 " href="https://jrb1995.gitee.io/tag/a-YytiE2t/">
            <span class="flex-auto">ios</span>
          </a>
        
          <a class="animated fadeInUp p-2 items-center text-sm text-gray-700 border hover:bg-gray-300 leading-none rounded-full flex lg:inline-flex m-4 " href="https://jrb1995.gitee.io/tag/oGDYGXS3n/">
            <span class="flex-auto">react-native</span>
          </a>
        


        <div class="flex justify-between py-8">
          

          
            <div class="next-post">
              <a href="https://jrb1995.gitee.io/post/vue-yuan-ma-fen-xi-xiang-ying-shi-yuan-li/">
                <h3 class="post-title">
                  Vue 源码分析 — 响应式原理
                  <i class="remixicon-arrow-right-line"></i>
                </h3>
              </a>
            </div>
          
        </div>

        
          
            <link rel="stylesheet" href="https://unpkg.com/gitalk/dist/gitalk.css">
<script src="https://unpkg.com/gitalk/dist/gitalk.min.js"></script>

<div id="gitalk-container"></div>

<script>

  var gitalk = new Gitalk({
    clientID: '58415ac62e821b4b6bbd',
    clientSecret: '69a93aa48149a7a74c6517efbbb32c57bc07799f',
    repo: 'jrb1995.github.io',
    owner: 'jrb1995',
    admin: ['jrb1995'],
    id: (location.pathname).substring(0, 49),      // Ensure uniqueness and length less than 50
    distractionFreeMode: false  // Facebook-like distraction free mode
  })

  gitalk.render('gitalk-container')

</script>

          

          
        

      </div>
    </div>

    <script src="https://jrb1995.gitee.io/media/prism.js"></script>  
<script>

Prism.highlightAll()

let mainNavLinks = document.querySelectorAll(".markdownIt-TOC a");

// This should probably be throttled.
// Especially because it triggers during smooth scrolling.
// https://lodash.com/docs/4.17.10#throttle
// You could do like...
// window.addEventListener("scroll", () => {
//    _.throttle(doThatStuff, 100);
// });
// Only not doing it here to keep this Pen dependency-free.

window.addEventListener("scroll", event => {
  let fromTop = window.scrollY;

  mainNavLinks.forEach((link, index) => {
    let section = document.getElementById(decodeURI(link.hash).substring(1));
    let nextSection = null
    if (mainNavLinks[index + 1]) {
      nextSection = document.getElementById(decodeURI(mainNavLinks[index + 1].hash).substring(1));
    }
    if (section.offsetTop <= fromTop) {
      if (nextSection) {
        if (nextSection.offsetTop > fromTop) {
          link.classList.add("current");
        } else {
          link.classList.remove("current");    
        }
      } else {
        link.classList.add("current");
      }
    } else {
      link.classList.remove("current");
    }
  });
});


document.addEventListener("DOMContentLoaded", function() {
  var lazyImages = [].slice.call(document.querySelectorAll(".post-feature-image.lazy"));

  if ("IntersectionObserver" in window) {
    let lazyImageObserver = new IntersectionObserver(function(entries, observer) {
      entries.forEach(function(entry) {
        if (entry.isIntersecting) {
          let lazyImage = entry.target
          lazyImage.style.backgroundImage = `url(${lazyImage.dataset.bg})`
          lazyImage.classList.remove("lazy")
          lazyImageObserver.unobserve(lazyImage)
        }
      });
    });

    lazyImages.forEach(function(lazyImage) {
      lazyImageObserver.observe(lazyImage)
    })
  } else {
    // Possibly fall back to a more compatible method here
  }
});

const menuContainer = document.querySelector('.menu-container')
const menus = document.querySelectorAll('.menu-container .menu')
const mask = document.querySelector('.mask')
const contentWrapper = document.querySelector('.content-wrapper')
const latestArticle = document.querySelector('.latest-article')
const readMore = document.querySelector('.read-more')
const indexPage = document.querySelector('.index-page')

const isHome = location.pathname === '/'
if (latestArticle) {
  latestArticle.style.display = isHome ? 'block' : 'none'
  readMore.style.display = isHome ? 'block' : 'none'
  indexPage.style.display = isHome ? 'none' : 'block'
}

const openMenu = () => {
  menuContainer.classList.add('open')
  menus.forEach(menu => {
    menu.classList.add('animated', 'fadeInLeft')
  })
  mask.classList.add('open')
  contentWrapper.classList.add('is-second')
}

const closeMenu = () => {
  menuContainer.classList.remove('open')
  menus.forEach(menu => {
    menu.classList.remove('animated', 'fadeInLeft')
  })
  mask.classList.remove('open')
  contentWrapper.classList.remove('is-second')
}
</script>
  
  </body>
</html>
